<template>
  <div
    class="img-container-wrapper position-relative"
  >
    <div
      class="full-box d-flex ai-c jc-c"
      v-if="loading"
    >
      加载中<span class="dot">...</span>
    </div>
    <div
      class="full-box d-flex ai-c jc-c bg-grey f-30"
      v-else-if="error"
    >
      <i class="el-icon-picture-outline" />
    </div>
    <img
      v-else
      ref="img"
      :src="src"
      @load="handleImgLoad"
      @error="handleImgError"
      @mousedown="handleMouseDown"
      :style="imgStyle"
      class="full-box"
      @click.right="clickRight"
    >
    <div
      class="el-image-viewer__btn el-image-viewer__actions"
      style="width: 182px;"
    >
      <div class="el-image-viewer__actions__inner">
        <i
          class="el-icon-zoom-out"
          @click="handleActions('zoomOut')"
        />
        <i
          class="el-icon-c-scale-to-original"
          @click="reset"
        />
        <i
          class="el-icon-zoom-in"
          @click="handleActions('zoomIn')"
        />
      </div>
    </div>
  </div>
</template>

<script>
import { on, off } from 'element-ui/src/utils/dom'
import { rafThrottle, isFirefox } from 'element-ui/src/utils/util'
const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'
export default {
  name: 'ImgContainer',
  props: {
    errorText: {
      type: String,
      default: '加载失败'
    },
    src: {
      type: String,
      required: true
    }
  },
  data () {
    return {
      loading: false,
      error: false,
      transform: {
        scale: 1,
        deg: 0,
        offsetX: 0,
        offsetY: 0,
        enableTransition: false
      }
    }
  },
  computed: {
    imgStyle () {
      const { scale, deg, offsetX, offsetY, enableTransition } = this.transform
      const style = {
        transform: `scale(${scale}) rotate(${deg}deg)`,
        transition: enableTransition ? 'transform .3s' : '',
        'margin-left': `${offsetX}px`,
        'margin-top': `${offsetY}px`,
        'object-fit': 'contain'
      }

      return style
    }
  },
  watch: {
    src (val) {
      this.loadImage()
    }
  },
  mounted () {
    this.loadImage()
    this.deviceSupportInstall()
  },
  methods: {
    loadImage () {
      if (!this.src) {
        console.log('没有传入图片路径')
        return
      }
      this.loading = true
      this.error = false
      const img = new Image()
      Object.keys(this.$attrs)
        .forEach((key) => {
          const value = this.$attrs[key]
          img.setAttribute(key, value)
        })
      img.src = this.src
      img.onload = e => this.handleImgLoad(e, img)
      img.onerror = e => this.handleImgError(e, img)
    },
    deviceSupportInstall () {
      this._mouseWheelHandler = rafThrottle(e => {
        const delta = e.wheelDelta ? e.wheelDelta : -e.detail
        if (delta > 0) {
          this.handleActions('zoomIn', {
            zoomRate: 0.1,
            enableTransition: false
          })
        } else {
          this.handleActions('zoomOut', {
            zoomRate: 0.1,
            enableTransition: false
          })
        }
      })
      on(document, mousewheelEventName, this._mouseWheelHandler)
    },
    deviceSupportUninstall () {
      off(document, mousewheelEventName, this._mouseWheelHandler)
      this._mouseWheelHandler = null
    },
    handleImgLoad (e, img) {
      this.loading = false
      this.error = false
    },
    handleImgError (e, img) {
      if (!img) return
      this.loading = false
      this.error = true
      console.log(e)
    },
    handleMouseDown (e) {
      if (this.loading || e.button !== 0) return

      const { offsetX, offsetY } = this.transform
      const startX = e.pageX
      const startY = e.pageY
      this._dragHandler = rafThrottle(ev => {
        this.transform.offsetX = offsetX + ev.pageX - startX
        this.transform.offsetY = offsetY + ev.pageY - startY
      })
      on(document, 'mousemove', this._dragHandler)
      on(document, 'mouseup', ev => {
        off(document, 'mousemove', this._dragHandler)
      })

      e.preventDefault()
    },
    handleActions (action, options = {}) {
      if (this.loading) return
      const { zoomRate, enableTransition } = {
        zoomRate: 0.2,
        rotateDeg: 90,
        enableTransition: true,
        ...options
      }
      const { transform } = this
      switch (action) {
        case 'zoomOut':
          if (transform.scale > 0.2) {
            transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3))
          }
          break
        case 'zoomIn':
          transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3))
          break
      }
      transform.enableTransition = enableTransition
    },
    reset () {
      this.transform = {
        scale: 1,
        deg: 0,
        offsetX: 0,
        offsetY: 0,
        enableTransition: false
      }
    },
    clickRight (e) {
      e.preventDefault()
    }
  },
  beforeDestroy () {
    this.deviceSupportUninstall()
  }
}
</script>
